<template>
  <div
    :class="{ fullscreen: fullscreen }"
    class="tinymce-container"
    :style="{ width: containerWidth }"
  >
    <!-- 文本域 -->
    <textarea :id="tinymceId" class="tinymce-textarea"/>
  </div>
</template>

<script>
import plugins from "./plugins";
import toolbar from "./toolbar";
import load from "./dynamicLoadScript";
import service from "@/utils/service"


const tinymceCDN = process.env.BASE_URL + 'tinymce/tinymce.min.js';


export default {
  name: "TinymceEditor",
  //用于接受父组件传递给子组件的数据
  props: {
    id: {
      type: String,
      default: function () {
        return (
          "vue-tinymce-" +
          +new Date() +
          ((Math.random() * 1000).toFixed(0) + "")
        );
      },
    },
    //富文本编辑器的值
    value: {
      type: String,
      default: "",
    },
    //编辑器的工具栏
    toolbar: {
      type: Array,
      required: false,
      default() {
        return [];
      },
    },
    //菜单栏
    menubar: {
      type: String,
      default: "file edit insert view format table help",
    },
    //编辑器的高度
    height: {
      type: [Number, String],
      required: false,
      default: 360,
    },
    //编辑器的宽度
    width: {
      type: [Number, String],
      required: false,
      default: "auto",
    },
  },
  data() {
    return {
      hasChange: false, //用于跟踪编辑器内容是否发生了变化
      hasInit: false, //用于跟踪编辑器是否已经初始化完成
      tinymceId: this.id,
      fullscreen: false, //用于跟踪编辑器是否处于全屏模式。
    };
  },
  //将 width 转换为带有单位 'px' 的字符串
  computed: {
    containerWidth() {
      const width = this.width;
      if (/^[\d]+(\.[\d]+)?$/.test(width)) {
        // matches `100`, `'100'`
        return `${width}px`;
      }
      return width;
    },
  },

  watch: {
    //将新的值 val 设置为编辑器的内容
    value(val) {
      if (!this.hasChange && this.hasInit) {
        this.$nextTick(() =>
          window.tinymce.get(this.tinymceId).setContent(val || "")
        );
      }
    },
  },
  mounted() {
    this.init();
  },
  activated() {
    //检查全局环境中是否已经加载了 TinyMCE 富文本编辑器库
    if (window.tinymce) {
      this.initTinymce();
    }
  },
  deactivated() {
    //当组件被停用时
    this.destroyTinymce();
  },
  destroyed() {
    this.destroyTinymce();
  },
  methods: {
    init() {
      // dynamic load tinymce from cdn
      load(tinymceCDN, (err) => {
        if (err) {
          this.$message.error(err.message);
          return;
        }
        window.tinymce.baseURL = window.location.origin + "/tinymce";
        this.initTinymce();
      });
    },
    initTinymce() {
      const _this = this;//为了应对回调函数中上下文发生变化
      window.tinymce.init({
        selector: `#${this.tinymceId}`, //定义了 TinyMCE 编辑器要附加到的 <textarea> 元素的选择器。
        promotion: false,//编辑器右上角的推荐升级的广告
        language: "zh_CN",
        content_style: "img {max-width:100%;}",
        placeholder: '在这里输入文字',
        min_height: this.height,
        font_family_formats:
          "微软雅黑='微软雅黑';宋体='宋体';黑体='黑体';仿宋='仿宋';楷体='楷体';隶书='隶书';幼圆='幼圆';Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Courier New=courier new,courier;Georgia=georgia,palatino;Webdings=webdings;Wingdings=wingdings;Times New Roman=times new roman", //字体选项
        body_class: "panel-body ",
        object_resizing: true, //配置是否允许用户调整编辑器中插入的对象（如图片）的大小。
        toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,//工具栏
        menubar: this.menubar,//菜单栏
        plugins: plugins,//插件
        end_container_on_empty_block: true, //控制在编辑器中的空块（没有内容的块级元素，如段落）的末尾是否添加一个 <br> 标签
        powerpaste_word_import: "clean", //TinyMCE 会尽量将粘贴的 Word 内容进行清理，以保持干净的格式。 prompt
        code_dialog_height: 450, //用于配置在插入代码块时显示的对话框的高度
        code_dialog_width: 1000,//用于配置在插入代码块时显示的对话框的宽度
        advlist_bullet_styles: "square,circle,disc", //无序列表中的项目符号
        advlist_number_styles:
          "lower-alpha,lower-roman,upper-alpha,upper-roman", //有序列表中的项目符号
        imagetools_cors_hosts: [], //跨域策略
        default_link_target: "_blank",
        link_title: false, //编辑器将不会显示链接的标题，即链接只显示链接文本，而不会显示额外的标题信息。
        nonbreaking_force_tab: true, // inserting nonbreaking space &nbsp; need Nonbreaking Space Plugin,
        init_instance_callback: (editor) => {
          if (_this.value) {
            editor.setContent(_this.value);  // 设置编辑器的内容为传入的 this.value 值
          }

          // 添加一个新的格式方案
          editor.formatter.register('my_custom_format', {
            block: 'p',
            styles: {
              'font-size': '14pt',
              'line-height': '1.5',
            }
          });

          // 自动应用该方案到任何新的段落
          editor.on('NewBlock', function(e) {
            editor.formatter.apply('my_custom_format');
          });

          // 应用该方案到已有内容和新的内容
          editor.formatter.apply('my_custom_format');

          _this.hasInit = true;

          // 当编辑器内容发生变化时，触发这个函数
          editor.on("NodeChange Change KeyUp SetContent", () => {
            this.hasChange = true;
            // 在内容发生变化时触发 this.$emit("input", editor.getContent())，
            this.$emit("input", editor.getContent());
          });
        },
        setup(editor) {
          //在编辑器全屏模式状态发生变化时触发事件 "FullscreenStateChanged"
          editor.on("FullscreenStateChanged", (e) => {
            _this.fullscreen = e.state;
          });
          editor.on("Init", (e)=>{
            editor.getBody().style.fontSize = '14pt';
          });
        },
        //上传图片、文件、视频
        // 自定义文件上传回调函数
        file_picker_callback: function (callback, value, meta) {
          // 文件分类
          var filetype = ".pdf, .txt, .zip, .rar, .7z, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .mp3, .mp4";
          // 后端接收上传文件的地址
          var upurl = "/teachers/upload";

          // 为不同插件指定文件类型及后端地址
          switch (meta.filetype) {
            case "image":
              filetype = ".jpg, .jpeg, .png, .gif";
              upurl = "/teachers/upload";
              break;
            case "media":
              filetype = ".mp3, .mp4";
              upurl = "/teachers/upload";
              break;
            case "file":
            default:
          }

          // 创建一个 FormData 对象，用于构建文件上传的数据
          var formData = new FormData();

          // 创建一个隐藏的 input 元素，用于选择文件
          var input = document.createElement("input");
          input.setAttribute("type", "file");
          input.setAttribute("accept", filetype);

          // 监听 input 元素的 change 事件
          input.onchange = function () {
            var file = this.files[0];
            var maxSizeInBytes = 100 * 1024 * 1024;

            if (file.size > maxSizeInBytes) {
              // 文件大小超过 100MB，触发错误回调
              _this.$message.error('文件大小超过100MB');
            } else {
              // 文件大小符合要求，继续上传
              formData.append("file", file, file.name);
              service.post(upurl, formData, {
                headers: {
                  Authorization: _this.$store.state.token,
                },
              })
                .then((response) => {
                  if (response.data.code === 20011) {
                    callback(response.data.data); // 返回文件在服务器的位置
                  } else {
                    callback("上传图片返回的数据无效");
                  }
                })
                .catch((error) => {
                  _this.$message.error("HTTP Error: " + error.message);
                });
            }
          };
          // 触发 input 元素的点击事件，打开文件选择对话框
          input.click();
        },

        convert_urls: false,
      });
    },
    destroyTinymce() {
      const tinymce = window.tinymce.get(this.tinymceId);
      if (this.fullscreen) {
        //使用 tinymce.execCommand("mceFullScreen") 方法退出全屏模式。这是一个 TinyMCE 的命令，用于切换编辑器的全屏状态。
        tinymce.execCommand("mceFullScreen");
      }

      if (tinymce) {
        tinymce.destroy();
      }
    },
    setContent(value) {
      window.tinymce.get(this.tinymceId).setContent(value);
    },
    getContent() {
      window.tinymce.get(this.tinymceId).getContent();
    },
  },
};
</script>

<style lang="scss" scoped>
.tinymce-container {
  position: relative;
  line-height: normal;
}

.tinymce-container {
  ::v-deep {
    .mce-fullscreen {
      z-index: 10000;
    }
  }
}

.tinymce-textarea {
  visibility: hidden;
  z-index: -1;
}


</style>
